package com.zhanpple.color_picker.library.circle

import android.annotation.SuppressLint
import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import androidx.annotation.FloatRange
import com.zhanpple.color_picker.library.ScreenSizeUtils
import kotlin.math.*

/**
 * @author zmp
 * @date 2018/6/20
 * HS色值饱和度选择器
 */
class CircleColorPicker @JvmOverloads constructor(
    context: Context?,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
    private val mPaint = Paint(Paint.ANTI_ALIAS_FLAG)
    private val mBgPaint = Paint(Paint.ANTI_ALIAS_FLAG)
    private var mRadius = 0F
    private val mPointF = PointF()
    private val mShapePadding by lazy {
        ScreenSizeUtils.dp2px(10F, resources)
    }

    override fun onSizeChanged(w: Int, h: Int, oldW: Int, oldH: Int) {
        super.onSizeChanged(w, h, oldW, oldH)
        mRadius = measuredWidth.coerceAtMost(measuredHeight) / 2F
        setSelectedPoint()
        setPaintShader()
    }

    private fun setPaintShader() {
        if (mRadius <= 0) {
            return
        }
        val mSweepGradient = SweepGradient(
            measuredWidth / 2f, measuredHeight / 2f,
            getColorH(),
            null
        )
        val radialGradient = RadialGradient(
            measuredWidth / 2f, measuredHeight / 2f,
            mRadius - mShapePadding, Color.WHITE, Color.TRANSPARENT, Shader.TileMode.CLAMP
        )
        val composeShader = ComposeShader(mSweepGradient, radialGradient, PorterDuff.Mode.SRC_OVER)
        mPaint.shader = composeShader
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        canvas.drawCircle(measuredWidth / 2F, measuredHeight / 2F, mRadius, mPaint)
        mBgPaint.color = Color.BLACK
        canvas.drawCircle(mPointF.x, mPointF.y, mShapePadding, mBgPaint)
        mBgPaint.color = Color.WHITE
        canvas.drawCircle(mPointF.x, mPointF.y, mShapePadding * 0.8F, mBgPaint)
    }

    /**
     * 创建光谱
     */
    private fun getColorH(): IntArray {
        val intArrayOf = IntArray(361)
        repeat(361) {
            intArrayOf[it] = Color.HSVToColor(floatArrayOf(it.toFloat(), 1f, mFloatArray[2]))
        }
        return intArrayOf
    }

    var mColorBack: ((Int) -> Unit)? = null

    private var mFloatArray = floatArrayOf(0F, 1F, 1F)


    /**
     * 设置颜色明度
     * @param v 明度
     */
    fun setColorValue(@FloatRange(from = 0.0, to = 1.0) v: Float, back: Boolean = true) {
        if (mFloatArray[2] != v) {
            mFloatArray[2] = v
        }
        setPaintShader()
        if (back) {
            mColorBack?.invoke(Color.HSVToColor(mFloatArray))
        }
        invalidate()
    }

    /**
     * 设置当前颜色
     * @param color 颜色
     */
    fun setCurrentColor(color: Int, back: Boolean = true) {
        Color.colorToHSV(color, mFloatArray)
        setSelectedPoint()
        setPaintShader()
        if (back) {
            mColorBack?.invoke(Color.HSVToColor(mFloatArray))
        }
        invalidate()
    }

    @SuppressLint("ClickableViewAccessibility")
    override fun onTouchEvent(event: MotionEvent): Boolean {
        val x = event.x - measuredWidth / 2F
        val y = event.y - measuredHeight / 2F
        var angle = atan2(y, x) * 180F / PI
        if (angle < 0) {
            angle += 360
        }
        mFloatArray[0] = angle.toFloat()
        mFloatArray[1] =
            (sqrt(x * x + y * y) / (mRadius - mShapePadding)).coerceAtMost(1F).coerceAtLeast(0F)
        mColorBack?.invoke(Color.HSVToColor(mFloatArray))
        setSelectedPoint()
        invalidate()
        return true
    }

    private fun setSelectedPoint() {
        var angle = mFloatArray[0]
        if (angle > 180) {
            angle -= 360
        }
        angle = (angle * PI / 180).toFloat()
        mPointF.x = cos(angle) * mFloatArray[1] * (mRadius - mShapePadding) + measuredWidth / 2F
        mPointF.y = sin(angle) * mFloatArray[1] * (mRadius - mShapePadding) + measuredHeight / 2F
    }

    init {
        setLayerType(LAYER_TYPE_SOFTWARE, null)
        setCurrentColor(Color.RED)
    }
}